home *** CD-ROM | disk | FTP | other *** search
/ EuroCD 3 / EuroCD 3.iso / Programming / PPCbwb111 / source / bwbasic.c < prev    next >
C/C++ Source or Header  |  1998-06-24  |  25KB  |  1,055 lines

  1. /***************************************************************
  2.  
  3.         bwbasic.c       Main Program File
  4.                         for Bywater BASIC Interpreter
  5.  
  6.                         Copyright (c) 1992, Ted A. Campbell
  7.  
  8.             "I was no programmer, neither was I a
  9.             programmer's son; but I was an herdman
  10.             and a gatherer of sycomore fruit."
  11.                  - Amos 7:14b AV, slightly adapted
  12.  
  13.                         Bywater Software
  14.                         P. O. Box 4023
  15.                         Duke Station
  16.                         Durham, NC  27706
  17.  
  18.                         email: tcamp@acpub.duke.edu
  19.  
  20.         Copyright and Permissions Information:
  21.  
  22.         All U.S. and international copyrights are claimed by the
  23.         author. The author grants permission to use this code
  24.         and software based on it under the following conditions:
  25.         (a) in general, the code and software based upon it may be
  26.         used by individuals and by non-profit organizations; (b) it
  27.         may also be utilized by governmental agencies in any country,
  28.         with the exception of military agencies; (c) the code and/or
  29.         software based upon it may not be sold for a profit without
  30.         an explicit and specific permission from the author, except
  31.         that a minimal fee may be charged for media on which it is
  32.         copied, and for copying and handling; (d) the code must be
  33.         distributed in the form in which it has been released by the
  34.         author; and (e) the code and software based upon it may not
  35.         be used for illegal activities.
  36.  
  37. ***************************************************************/
  38.  
  39. #include <stdio.h>
  40. #include <stdlib.h>
  41. #include <ctype.h>
  42. #include <string.h>
  43. #include <math.h>
  44. #include <signal.h>
  45. #include <setjmp.h>
  46.  
  47. #include "bwbasic.h"
  48. #include "bwb_mes.h"
  49.  
  50. char bwb_progfile[ MAXARGSIZE ];
  51. struct bwb_line bwb_start, bwb_end;
  52. char *bwb_ebuf;                /* error buffer */
  53. static char *read_line;
  54. int bwb_trace = FALSE;
  55. int bwb_number = 0;
  56. struct bwb_line *bwb_l;
  57.  
  58. struct xtxtsl
  59.    {
  60.    int  position;
  61.    struct bwb_line l;
  62.    };
  63.  
  64. struct xtxtsl *xtxts;                /* eXecute TeXT stack */
  65. struct exp_ese *exp_es;            /* expression stack */
  66. struct ufsel *ufs;                  /* user function stack */
  67. struct fse *fs;                         /* FOR stack */
  68.  
  69. int xtxtsc = -1;                        /* eXecute TeXT stack counter */
  70.  
  71. FILE *errfdevice;                       /* output device for error messages */
  72. static jmp_buf mark;
  73. static int program_run = FALSE;        /* has the command-line program ben run? */
  74.  
  75. /* Prototypes for functions visible only to this file */
  76.  
  77. #if COMMAND_SHELL
  78. static int bwb_shell( struct bwb_line *l );
  79. #endif
  80.  
  81. extern int is_ln( char *buffer );
  82.  
  83. /***************************************************************
  84.  
  85.         FUNCTION:       main()
  86.  
  87.         DESCRIPTION:    As in any C program, main() is the basic
  88.                         function from which the rest of the
  89.                         program is called.
  90.  
  91.     PRAYER:        Everlasting God,
  92.  
  93.             Thine eternal Logos is the main() function
  94.             from which all things have their being
  95.             and unto which all things shall return;
  96.             all subroutines are restless until they
  97.             find their rest in thee.
  98.  
  99.             Grant that users of this software may
  100.             apply it for good purposes; grant
  101.             unto programmers searching its ways that
  102.             they may not be entirely confounded; and
  103.             grant that all our work may be unto thy
  104.             glory. Amen.
  105.  
  106. ***************************************************************/
  107.  
  108. void
  109. main( int argc, char **argv )
  110.    {
  111.    static FILE *input = NULL;
  112.    static int jump_set = FALSE;
  113.    static char start_buf[] = "\0";
  114.    static char end_buf[] = "\0";
  115.    register int n;
  116. #if REDIRECT_STDERR
  117.    FILE *newerr;
  118. #endif
  119.  
  120.    /* set some initial variables */
  121.  
  122.    bwb_start.number = 0;
  123.    bwb_start.next = &bwb_end;
  124.    bwb_end.number = MAXLINENO + 1;
  125.    bwb_end.next = &bwb_end;
  126.    bwb_start.buffer = start_buf;
  127.    bwb_end.buffer = end_buf;
  128.    data_line = &bwb_start;
  129.    data_pos = 0;
  130.  
  131.    /* Memory allocation for various tables */
  132.  
  133.    /* eXecute TeXT stack */
  134.  
  135.    if ( ( xtxts = calloc( XTXTSTACKSIZE, sizeof( struct xtxtsl ) ) ) == NULL )
  136.       {
  137.       bwb_error( err_getmem );
  138.       }
  139.  
  140.    /* expression stack */
  141.  
  142.    if ( ( exp_es = calloc( ESTACKSIZE, sizeof( struct exp_ese ) ) ) == NULL )
  143.       {
  144.       bwb_error( err_getmem );
  145.       }
  146.  
  147.    /* user-defined function stack */
  148.  
  149.    if ( ( ufs = calloc( UFNCSTACKSIZE, sizeof( struct ufsel ) ) ) == NULL )
  150.       {
  151.       bwb_error( err_getmem );
  152.       }
  153.  
  154.    /* FOR-NEXT stack */
  155.  
  156.    if ( ( fs = calloc( FORLEVELS, sizeof( struct fse ) ) ) == NULL )
  157.       {
  158.       bwb_error( err_getmem );
  159.       }
  160.  
  161.    /* GOSUB-RETURN stack */
  162.  
  163.    if ( ( bwb_gss = calloc( GOSUBLEVELS, sizeof( struct gsse ) ) ) == NULL )
  164.       {
  165.       bwb_error( err_getmem );
  166.       }
  167.  
  168.    /* character buffers */
  169.  
  170.    if ( ( bwb_ebuf = calloc( MAXSTRINGSIZE + 1, sizeof(char) ) ) == NULL )
  171.       {
  172.       bwb_error( err_getmem );
  173.       }
  174.    if ( ( read_line = calloc( MAXREADLINESIZE + 1, sizeof(char) ) ) == NULL )
  175.       {
  176.       bwb_error( err_getmem );
  177.       }
  178.  
  179.    /* Variable and function table initializations */
  180.  
  181.    var_init();                  /* initialize variable chain */
  182.  
  183.    fnc_init();                  /* initialize function chain */
  184.  
  185. #if TEST_BSTRING
  186.    for ( n = 0; n < ESTACKSIZE; ++n )
  187.       {
  188.       sprintf( exp_es[ n ].sval.name, "<Exp stack bstring %d>", n );
  189.       }
  190. #endif
  191.  
  192.    /* assign memory for the device table */
  193.  
  194.    if ( ( dev_table = calloc( DEF_DEVICES, sizeof( struct dev_element ) ) ) == NULL )
  195.       {
  196.       bwb_error( err_getmem );
  197.       exit(-1);
  198.       }
  199.  
  200.    /* initialize all devices to DEVMODE_AVAILABLE */
  201.  
  202.    for ( n = 0; n < DEF_DEVICES; ++n )
  203.       {
  204.       dev_table[ n ].mode = DEVMODE_AVAILABLE;
  205.       dev_table[ n ].reclen = -1;
  206.       dev_table[ n ].cfp = NULL;
  207.       dev_table[ n ].buffer = NULL;
  208.       dev_table[ n ].width = DEF_WIDTH;
  209.       dev_table[ n ].col = 1;
  210.       }
  211.  
  212.    /* Signon message */
  213.  
  214.    sprintf( bwb_ebuf, "\r%s %s\n", MES_SIGNON, VERSION );
  215.    xprintf( stdout, bwb_ebuf );
  216.    sprintf( bwb_ebuf, "\r%s\n", MES_COPYRIGHT );
  217.    xprintf( stdout, bwb_ebuf );
  218. #if PERMANENT_DEBUG
  219.    sprintf( bwb_ebuf, "\r%s\n", "DEBUGGING MODE" );
  220.    xprintf( stdout, bwb_ebuf );
  221. #else
  222.    sprintf( bwb_ebuf, "\r%s\n", MES_LANGUAGE );
  223.    xprintf( stdout, bwb_ebuf );
  224. #endif
  225.  
  226.    /* Redirect stderr if specified */
  227.  
  228. #if REDIRECT_STDERR
  229.    newerr = freopen( ERRFILE, "w", stderr );
  230.    if ( newerr == NULL )
  231.       {
  232.       sprintf( bwb_ebuf, "Failed to redirect error messages to file <%s>\n",
  233.          ERRFILE );
  234.       xprintf( stdout, bwb_ebuf );
  235.       errfdevice = stdout;
  236.       }
  237.    else
  238.       {
  239.       sprintf( bwb_ebuf, "NOTE: Error messages are redirected to file <%s>\n",
  240.          ERRFILE );
  241.       xprintf( errfdevice, bwb_ebuf );
  242.       errfdevice = stderr;
  243.       }
  244. #else
  245.    errfdevice = stdout;
  246. #endif
  247.  
  248. #if INTENSIVE_DEBUG
  249.    sprintf( bwb_ebuf, "in main(): Ready to save jump MARKER" );
  250.    bwb_debug( bwb_ebuf );
  251.    getchar();
  252. #endif
  253.  
  254.    /* set a buffer for jump: program execution returns to this point
  255.       in case of a jump (error, interrupt, or finish program) */
  256.  
  257.    signal( SIGINT, break_mes );
  258.    setjmp( mark );
  259.  
  260. #if INTENSIVE_DEBUG
  261.    sprintf( bwb_ebuf, "in main(): Return from jump MARKER, program run <%d>",
  262.       program_run );
  263.    bwb_debug( bwb_ebuf );
  264.    getchar();
  265. #endif
  266.  
  267.    /* check to see if there is a program file: but do this only the first
  268.       time around! */
  269.  
  270.    if (( argc > 1 ) && ( program_run == FALSE ))
  271.       {
  272.       program_run = TRUE;            /* don't do it again */
  273.       if ( ( input = fopen( argv[ 1 ], "r" )) == NULL )
  274.          {
  275.          strcpy( bwb_progfile, argv[ 1 ] );
  276.          strcat( bwb_progfile, ".bas" );
  277.          if ( ( input = fopen( bwb_progfile, "r" )) == NULL )
  278.             {
  279.             bwb_progfile[ 0 ] = 0;
  280.             sprintf( bwb_ebuf, err_openfile, argv[ 1 ] );
  281.             bwb_error( bwb_ebuf );
  282.             }
  283.          }
  284.       if ( input != NULL )
  285.          {
  286.          strcpy( bwb_progfile, argv[ 1 ] );
  287. #if INTENSIVE_DEBUG
  288.          sprintf( bwb_ebuf, "in main(): progfile is <%s>.", bwb_progfile );
  289.          bwb_debug( bwb_ebuf );
  290. #endif
  291.          bwb_fload( input );
  292.          bwb_run( &bwb_start );
  293.          }
  294.       }
  295.  
  296.    /* Main Program Loop */
  297.  
  298.    while( !feof( stdin ) )        /* condition !feof( stdin ) added in v1.11 */
  299.       {                    /* to deal with possible of ^D etc. in Unix */
  300.  
  301.       /* take input from keyboard */
  302.  
  303.       bwb_gets( read_line );
  304.  
  305.       /* If there is no line number, execute the line as received */
  306.  
  307.       if ( is_ln( read_line ) == FALSE )
  308.          {
  309.          bwb_xtxtline( read_line );
  310.          }
  311.  
  312.       /* If there is a line number, add the line to the file in memory */
  313.  
  314.       else
  315.          {
  316.          bwb_ladd( read_line, TRUE );
  317.          }
  318.  
  319.       }
  320.  
  321.    }
  322.  
  323. /***************************************************************
  324.  
  325.         FUNCTION:       bwb_fload()
  326.  
  327.         DESCRIPTION: This function loads a BASIC program
  328.         file into memory.
  329.  
  330. ***************************************************************/
  331.  
  332. bwb_fload( FILE *file )
  333.    {
  334.  
  335.    while ( feof( file ) == FALSE )
  336.       {
  337.       read_line[ 0 ] = '\0';
  338.       fgets( read_line, MAXREADLINESIZE, file );
  339.       if ( file == stdin )
  340.          {
  341.          * prn_getcol( stdout ) = 1;        /* reset column */
  342.          }
  343.       bwb_stripcr( read_line );
  344.       bwb_ladd( read_line, FALSE );
  345.       }
  346.  
  347.    /* close file stream */
  348.  
  349.    fclose( file );
  350.  
  351.    return TRUE;
  352.    }
  353.  
  354. /***************************************************************
  355.  
  356.         FUNCTION:       bwb_ladd()
  357.  
  358.         DESCRIPTION:    This function adds a new line (in the
  359.                         buffer) to the program in memory.
  360.  
  361. ***************************************************************/
  362.  
  363. bwb_ladd( char *buffer, int replace )
  364.    {
  365.    struct bwb_line *l, *previous;
  366.    register int n, a;
  367.    static char *s_buffer;
  368.    static int init = FALSE;
  369.    static int prev_num = 0;
  370.  
  371. #if INTENSIVE_DEBUG
  372.    sprintf( bwb_ebuf, "in bwb_ladd(): ready to get memory for <%s>",
  373.       buffer );
  374.    bwb_debug( bwb_ebuf );
  375. #endif
  376.  
  377.    /* get memory for temporary buffer if necessary */
  378.  
  379.    if ( init == FALSE )
  380.       {
  381.       init = TRUE;
  382.       if ( ( s_buffer = calloc( (size_t) MAXSTRINGSIZE + 1, sizeof( char ) )) == NULL )
  383.          {
  384.          bwb_error( err_getmem );
  385.          return FALSE;
  386.          }
  387.       }
  388.  
  389.    /* get memory for this line */
  390.  
  391.    if ( ( l = (struct bwb_line *) calloc( (size_t) 1, sizeof( struct bwb_line ) )) == NULL )
  392.       {
  393.       bwb_error( err_getmem );
  394.       return FALSE;
  395.       }
  396.  
  397. #if INTENSIVE_DEBUG
  398.    sprintf( bwb_ebuf, "in bwb_ladd(): got memory." );
  399.    bwb_debug( bwb_ebuf );
  400. #endif
  401.  
  402.    /* allocate memory and assign buffer to line buffer */
  403.  
  404.    ln_asbuf( l, buffer );
  405.  
  406.    /* get the first element and test for a line number */
  407.  
  408.    adv_element( l->buffer, &( l->position ), s_buffer );
  409.  
  410.    /* note that line is not yet marked */
  411.  
  412.    l->marked = FALSE;
  413.  
  414.    /* set line number in line structure */
  415.  
  416.    if ( is_numconst( s_buffer ) == TRUE )
  417.       {
  418.       l->number = atoi( s_buffer );
  419.       prev_num = l->number;
  420.       }
  421.    else
  422.       {
  423.  
  424. #if INTENSIVE_DEBUG
  425.       sprintf( bwb_ebuf, "in bwb_ladd(): line is not numbered, using prev <%d>",
  426.          prev_num );
  427.       bwb_debug( bwb_ebuf );
  428. #endif
  429.  
  430.       l->number = prev_num;
  431.       }
  432.  
  433.    /* find the place of the current line */
  434.  
  435.    for ( previous = &bwb_start; previous != &bwb_end; previous = previous->next )
  436.       {
  437.  
  438.       /* replace a previously existing line */
  439.  
  440.       if (( previous->number == l->number ) && ( replace == TRUE ))
  441.          {
  442.  
  443. #if INTENSIVE_DEBUG
  444.          sprintf( bwb_ebuf, "in bwb_ladd(): writing to previous number." );
  445.          bwb_debug( bwb_ebuf );
  446. #endif
  447.  
  448.          /* allocate memory and assign buffer to line buffer */
  449.  
  450.          ln_asbuf( previous, buffer );
  451.  
  452.          /* free the current line */
  453.  
  454.          free( l );
  455.  
  456.          /* and return */
  457.  
  458.          return TRUE;
  459.  
  460.          }
  461.  
  462.       /* add after previously existing line: this is to allow unnumbered
  463.          lines that follow in sequence after a previously numbered line */
  464.  
  465.       else if (( previous->number == l->number ) && ( replace == FALSE ))
  466.          {
  467. #if INTENSIVE_DEBUG
  468.          sprintf( bwb_ebuf, "in bwb_ladd(): adding doubled number <%d>",
  469.             l->number );
  470.          bwb_debug( bwb_ebuf);
  471. #endif
  472.          l->next = previous->next;
  473.          previous->next = l;
  474.          return TRUE;
  475.          }
  476.  
  477.       /* add a new line */
  478.  
  479.       else if ( ( previous->number < l->number )
  480.          && ( previous->next->number > l->number ))
  481.          {
  482.          l->next = previous->next;
  483.          previous->next = l;
  484.  
  485. #if INTENSIVE_DEBUG
  486.          sprintf( bwb_ebuf, "in bwb_ladd(): added new line <%d> buffer <%s>",
  487.             l->number, l->buffer );
  488.          bwb_debug( bwb_ebuf );
  489. #endif
  490.  
  491.          return TRUE;
  492.          }
  493.  
  494.       }
  495.  
  496.    sprintf( bwb_ebuf, ERR_LINENO );
  497.    bwb_error( bwb_ebuf );
  498.    return FALSE;
  499.  
  500.    }
  501.  
  502. /***************************************************************
  503.  
  504.         FUNCTION:       bwb_shell()
  505.  
  506.         DESCRIPTION:
  507.  
  508. ***************************************************************/
  509.  
  510. #if COMMAND_SHELL
  511. static int
  512. bwb_shell( struct bwb_line *l )
  513.    {
  514.    static char *s_buffer;
  515.    static int init = FALSE;
  516.    static int position;
  517.  
  518.    /* get memory for temporary buffer if necessary */
  519.  
  520.    if ( init == FALSE )
  521.       {
  522.       init = TRUE;
  523.       if ( ( s_buffer = calloc( MAXSTRINGSIZE + 1, sizeof( char ) )) == NULL )
  524.          {
  525.          bwb_error( err_getmem );
  526.          return FALSE;
  527.          }
  528.       }
  529.  
  530.    /* get the first element and check for a line number */
  531.  
  532. #if INTENSIVE_DEBUG
  533.    sprintf( bwb_ebuf, "in bwb_shell(): line buffer is <%s>.", l->buffer );
  534.    bwb_debug( bwb_ebuf );
  535. #endif
  536.  
  537.    position = 0;
  538.    adv_element( l->buffer, &position, s_buffer );
  539.    if ( is_numconst( s_buffer ) != TRUE )                  /* not a line number */
  540.       {
  541.  
  542. #if INTENSIVE_DEBUG
  543.       sprintf( bwb_ebuf, "in bwb_shell(): no line number, command <%s>.",
  544.          l->buffer );
  545.       bwb_debug( bwb_ebuf );
  546. #endif
  547.  
  548.       if ( system( l->buffer ) == 0 )
  549.          {
  550.          return TRUE;
  551.          }
  552.       else
  553.          {
  554.          return FALSE;
  555.          }
  556.       }
  557.  
  558.    else                                         /* advance past line number */
  559.       {
  560.       adv_ws( l->buffer, &position );           /* advance past whitespace */
  561.  
  562. #if INTENSIVE_DEBUG
  563.       sprintf( bwb_ebuf, "in bwb_shell(): line number, command <%s>.",
  564.          l->buffer );
  565.       bwb_debug( bwb_ebuf );
  566. #endif
  567.  
  568.       if ( system( &( l->buffer[ position ] ) ) == 0 )
  569.          {
  570.          return TRUE;
  571.          }
  572.       else
  573.          {
  574.          return FALSE;
  575.          }
  576.       }
  577.    }
  578. #endif
  579.  
  580. /***************************************************************
  581.  
  582.         FUNCTION:       bwb_xtxtline()
  583.  
  584.         DESCRIPTION:    This function executes a text line, i.e.,
  585.                         places it in memory and then calls
  586.                         bwb_xline() to execute it.
  587.  
  588. ***************************************************************/
  589.  
  590. struct bwb_line *
  591. bwb_xtxtline( char *buffer )
  592.    {
  593.    struct bwb_line *c;
  594.    register int n, a;
  595.    char *p;
  596.    int loop;
  597.  
  598. #if INTENSIVE_DEBUG
  599.    sprintf( bwb_ebuf, "in bwb_xtxtline(): received <%s>", buffer );
  600.    bwb_debug( bwb_ebuf );
  601. #endif
  602.  
  603.    /* increment xtxt stack counter */
  604.  
  605.    if ( xtxtsc >= XTXTSTACKSIZE )
  606.       {
  607.       sprintf( bwb_ebuf, "Exceeded maximum xtxt stack <%d>",
  608.          xtxtsc );
  609.       return &bwb_end;
  610.       }
  611.  
  612.    ++xtxtsc;
  613.  
  614.    /* advance past whitespace */
  615.  
  616.    p = buffer;
  617.    loop = TRUE;
  618.    while( loop == TRUE )
  619.       {
  620.  
  621.       switch( *p )
  622.          {
  623.          case '\0':                     /* end of string */
  624.  
  625. #if INTENSIVE_DEBUG
  626.             sprintf( bwb_ebuf, "Null command line received." );
  627.             bwb_debug( bwb_ebuf );
  628. #endif
  629.             --xtxtsc;
  630.             return &bwb_end;
  631.          case ' ':                      /* whitespace */
  632.          case '\t':
  633.             ++p;
  634.             break;
  635.          default:
  636.             loop = FALSE;
  637.             break;
  638.          }
  639.  
  640.       }
  641.  
  642. #if INTENSIVE_DEBUG
  643.    sprintf( bwb_ebuf, "in bwb_xtxtline(): ready to get memory" );
  644.    bwb_debug( bwb_ebuf );
  645. #endif
  646.  
  647.    if ( xtxts[ xtxtsc ].l.buffer != NULL )
  648.       {
  649. #if INTENSIVE_DEBUG
  650.       sprintf( bwb_ebuf, "in bwb_xtxtline(): freeing buffer memory" );
  651.       bwb_debug( bwb_ebuf );
  652. #endif
  653.       free( xtxts[ xtxtsc ].l.buffer );
  654.       }
  655.  
  656.    /* copy the whole line to the line structure buffer */
  657.  
  658.    ln_asbuf( &( xtxts[ xtxtsc ].l ), buffer );
  659.  
  660. #if INTENSIVE_DEBUG
  661.    sprintf( bwb_ebuf, "in bwb_xtxtline(): copied to line buffer <%s>.",
  662.       xtxts[ xtxtsc ].l.buffer );
  663.    bwb_debug( bwb_ebuf );
  664. #endif
  665.  
  666.    /* set line number in line structure */
  667.  
  668.    xtxts[ xtxtsc ].l.number = 0;
  669.    xtxts[ xtxtsc ].l.marked = FALSE;
  670.  
  671.    /* execute the line as BASIC command line */
  672.  
  673.    xtxts[ xtxtsc ].l.next = &bwb_end;
  674.    c = &( xtxts[ xtxtsc ].l );
  675.    c->position = 0;
  676.  
  677.    do
  678.       {
  679. /*      xtxts[ xtxtsc ].position = 0; */
  680.       c = bwb_xline( c );
  681.       }
  682.  
  683.    while( c != &bwb_end );
  684.  
  685.    /* decrement xtxt stack counter */
  686.  
  687.    --xtxtsc;
  688.  
  689.    return c;
  690.  
  691.    }
  692.  
  693. /***************************************************************
  694.  
  695.         FUNCTION:       bwb_xline()
  696.  
  697.         DESCRIPTION:    This function executes a single line of
  698.                         the program in memory.
  699.  
  700. ***************************************************************/
  701.  
  702. struct bwb_line *
  703. bwb_xline( struct bwb_line *l )
  704.    {
  705.    int loop, extended_line;
  706.    struct bwb_line *r;
  707.  
  708. #if INTENSIVE_DEBUG
  709.    sprintf( bwb_ebuf, "in bwb_xline(): buffer <%s>",
  710.       &( l->buffer[ l->position ] ) );
  711.    bwb_debug( bwb_ebuf );
  712. #endif
  713.  
  714.    /* Print line number if trace is on */
  715.  
  716.    if ( bwb_trace == TRUE )
  717.       {
  718.       if ( l->number > 0 )
  719.          {
  720.          sprintf( bwb_ebuf, "[ %d ]", l->number );
  721.          xprintf( errfdevice, bwb_ebuf );
  722.          }
  723.       }
  724.  
  725.    /* Set current line for error/break handling */
  726.  
  727.    bwb_number = l->number;
  728.    bwb_l = l;
  729.    extended_line = FALSE;
  730.  
  731.    /* advance past whitespace and segment delimiter */
  732.  
  733.    if ( l->buffer[ l->position ] == ':' )
  734.       {
  735.       ++( l->position );
  736.       }
  737.    adv_ws( l->buffer, &( l->position ) );
  738.    if ( l->buffer[ l->position ] == ':' )
  739.       {
  740.       ++( l->position );
  741.       adv_ws( l->buffer, &( l->position ) );
  742.       }
  743.  
  744.    /* Loop through line segments delimited by ':' */
  745.  
  746.    loop = TRUE;
  747.    r = l->next;
  748.  
  749.    while ( loop == TRUE )
  750.       {
  751.  
  752.       /* set loop to false: it will be set to TRUE later if needed */
  753.  
  754.       loop = FALSE;
  755.  
  756.       /* set positions in buffer */
  757.  
  758. #if MARK_LINES
  759.       if ( ( l->marked != TRUE ) || ( l->position > l->startpos ))
  760.      {
  761.      line_start( l->buffer, &( l->position ), &( l->lnpos ), &( l->lnum ),
  762.         &( l->cmdpos ), &( l->cmdnum ), &( l->startpos ) );
  763.      l->marked = TRUE;
  764.      }
  765.       else
  766.          {
  767. #if INTENSIVE_DEBUG
  768.          sprintf( bwb_ebuf, "in bwb_xline(): line <%d> is already marked",
  769.              l->number );
  770.          bwb_debug( bwb_ebuf );
  771. #endif
  772.          }
  773. #else
  774.       line_start( l->buffer, &( l->position ), &( l->lnpos ), &( l->lnum ),
  775.          &( l->cmdpos ), &( l->cmdnum ), &( l->startpos ) );
  776. #endif
  777.  
  778.       if ( l->position < l->startpos )
  779.          {
  780.          l->position = l->startpos;
  781.          }
  782.  
  783.       /* if there is a BASIC command in the line, execute it here */
  784.  
  785.       if ( l->cmdnum > -1 )
  786.          {
  787.  
  788. #if INTENSIVE_DEBUG
  789.          sprintf( bwb_ebuf, "in bwb_xline(): executing <%s>", l->buffer );
  790.          bwb_debug( bwb_ebuf );
  791. #endif
  792.  
  793.          /* execute the command vector */
  794.  
  795.          r = ( bwb_cmdtable[ l->cmdnum ].vector ) ( l );
  796.  
  797. #if INTENSIVE_DEBUG
  798.      if ( l->cmdnum == getcmdnum( "GOSUB" ) )
  799.         {
  800.         sprintf( bwb_ebuf, "in bwb_xline(): returning from GOSUB, position <%d>",
  801.            l->position );
  802.         bwb_debug( bwb_ebuf );
  803.             }
  804. #endif
  805.  
  806.          /* If the command was RETURN OR GOTO, then we must break out of
  807.             the loop at this point; the rest of the line is irrelevant */
  808.  
  809.          if ( l->cmdnum == getcmdnum( "RETURN" ) )
  810.             {
  811. #if INTENSIVE_DEBUG
  812.         sprintf( bwb_ebuf, "in bwb_xline(): returning from RETURN command, ret line <%d>",
  813.            r->number );
  814.         bwb_debug( bwb_ebuf );
  815. #endif
  816.         r->cmdnum = getcmdnum( "RETURN" );
  817.         r->marked = FALSE;
  818.         return r;            /* break out; return now */
  819.         }
  820.  
  821.          else if ( l->cmdnum == getcmdnum( "GOTO" ) )
  822.             {
  823. #if INTENSIVE_DEBUG
  824.             sprintf( bwb_ebuf, "in bwb_xline(): returning from GOTO command, ret line <%d>",
  825.                r->number );
  826.             bwb_debug( bwb_ebuf );
  827. #endif
  828.             return r;
  829.             }
  830.          }
  831.  
  832.       else if ( l->buffer[ l->position ] == ':' )
  833.          {
  834.          l->marked = FALSE;
  835.          }                /* do nothing */
  836.  
  837.       /* No BASIC command; try to execute it as a shell command */
  838.  
  839. #if COMMAND_SHELL
  840.       else
  841.      {
  842.  
  843. #if INTENSIVE_DEBUG
  844.      sprintf( bwb_ebuf, "Breaking out to shell, line num <%d> buf <%s> cmd <%d> pos <%d>",
  845.         l->number, &( l->buffer[ l->position ] ), l->cmdnum, l->position );
  846.      bwb_debug( bwb_ebuf );
  847.      getchar();
  848. #endif
  849.  
  850.      bwb_shell( l );
  851.      }
  852.  
  853. #else                /* COMMAND_SHELL == FALSE */
  854.  
  855.       else
  856.         {
  857.         bwb_error( err_uc );
  858.         }
  859.  
  860. #endif
  861.  
  862.       /* detect if the current character is ':', in which case loop
  863.          back through to execute it */
  864.  
  865. #if INTENSIVE_DEBUG
  866.       sprintf( bwb_ebuf, "in bwb_xline(): remaining line is <%s>",
  867.          &( l->buffer[ l->position ] ) );
  868.       bwb_debug( bwb_ebuf );
  869. #endif
  870.  
  871.       adv_ws( l->buffer, &( l->position ) );
  872.       if ( l->buffer[ l->position ] == ':' )
  873.          {
  874.  
  875. #if INTENSIVE_DEBUG
  876.      sprintf( bwb_ebuf, "in bwb_xline(): line <%d> found \':\'",
  877.         l->number );
  878.          bwb_debug( bwb_ebuf );
  879. #endif
  880.  
  881.      ++l->position;
  882.      l->marked = FALSE;
  883.      extended_line = TRUE;
  884.          loop = TRUE;
  885.          }
  886.  
  887.       else if ( extended_line == TRUE )
  888.      {
  889.      l->marked = FALSE;
  890.      }
  891.  
  892.       }                                 /* end of loop through line */
  893.  
  894.    /* return the value in r */
  895.  
  896. #if INTENSIVE_DEBUG
  897.    if ( r->cmdnum == getcmdnum( "RETURN" ) )
  898.       {
  899.       bwb_debug( "in bwb_xline(): returning RETURN cmdnum" );
  900.       }
  901. #endif
  902.  
  903.    return r;
  904.  
  905.    }
  906.  
  907. /***************************************************************
  908.  
  909.         FUNCTION:       ln_asbuf()
  910.  
  911.         DESCRIPTION:    This function allocates memory and copies
  912.             a null-terminated string to a line buffer.
  913.  
  914. ***************************************************************/
  915.  
  916. int
  917. ln_asbuf( struct bwb_line *l, char *s )
  918.    {
  919.  
  920. #ifdef DONTDOIT
  921.    if ( l->buffer != NULL )
  922.       {
  923.       free( l->buffer );
  924.       }
  925. #endif
  926.  
  927.    if ( ( l->buffer = calloc( strlen( s ) + 2, sizeof( char ) ) )
  928.       == NULL )
  929.       {
  930.       bwb_error( err_getmem );
  931.       return FALSE;
  932.       }
  933.  
  934.    /* copy the whole line to the line structure buffer */
  935.  
  936.    strcpy( l->buffer, s );
  937.  
  938. #if INTENSIVE_DEBUG
  939.    sprintf( bwb_ebuf, "in ln_asbuf(): allocated buffer <%s>", l->buffer );
  940.    bwb_debug( bwb_ebuf );
  941. #endif
  942.  
  943.    /* strip CR from the buffer */
  944.  
  945.    bwb_stripcr( l->buffer );
  946.  
  947.    return TRUE;
  948.  
  949.    }
  950.  
  951. /***************************************************************
  952.  
  953.         FUNCTION:       bwb_gets()
  954.  
  955.         DESCRIPTION:    This function reads a single line from
  956.                         the specified buffer.
  957.  
  958. ***************************************************************/
  959.  
  960. bwb_gets( char *buffer )
  961.    {
  962.    bwb_number = 0;
  963.    sprintf( bwb_ebuf, "\r%s\n", PROMPT );
  964.    xprintf( stdout, bwb_ebuf );
  965.  
  966.    fgets( buffer, MAXREADLINESIZE, stdin );
  967.    * prn_getcol( stdout ) = 1;            /* reset column */
  968.    return TRUE;
  969.    }
  970.  
  971. /***************************************************************
  972.  
  973.         FUNCTION:       break_mes()
  974.  
  975.         DESCRIPTION:    This function is called (a) by a SIGINT
  976.                         signal or (b) by error-handling routines.
  977.  
  978. ***************************************************************/
  979.  
  980. void
  981. break_mes( int x )
  982.    {
  983.    static char *tmp_buffer;
  984.    static int init = FALSE;
  985.  
  986.    /* get memory for temporary buffer if necessary */
  987.  
  988.    if ( init == FALSE )
  989.       {
  990.       init = TRUE;
  991.       if ( ( tmp_buffer = calloc( MAXSTRINGSIZE + 1, sizeof( char ) )) == NULL )
  992.          {
  993.          bwb_error( err_getmem );
  994.          }
  995.       }
  996.  
  997.    exp_esc = 0;
  998.  
  999.    sprintf( tmp_buffer, "\r%s %d\n", MES_BREAK, bwb_number );
  1000.    xprintf( errfdevice, tmp_buffer );
  1001.  
  1002.    break_handler();
  1003.  
  1004.    }
  1005.  
  1006. void
  1007. break_handler( void )
  1008.    {
  1009.  
  1010.    /* zero all stack counters */
  1011.  
  1012.    exp_esc = 0;
  1013.    bwb_gssc = 0;
  1014.    ufsc = 0;
  1015.    ws_counter = 0;
  1016.    fs_counter = 0;
  1017.    xtxtsc = 0;
  1018.  
  1019.    /* reset the break handler */
  1020.  
  1021.    signal( SIGINT, break_mes );
  1022.  
  1023.    /* jump back to mark */
  1024.  
  1025.    longjmp( mark, -1 );
  1026.  
  1027.    }
  1028.  
  1029.  
  1030. int
  1031. is_ln( char *buffer )
  1032.    {
  1033.    static int position;
  1034.  
  1035.    position = 0;
  1036.    adv_ws( buffer, &position );
  1037.    switch( buffer[ position ] )
  1038.       {
  1039.       case '0':
  1040.       case '1':
  1041.       case '2':
  1042.       case '3':
  1043.       case '4':
  1044.       case '5':
  1045.       case '6':
  1046.       case '7':
  1047.       case '8':
  1048.       case '9':
  1049.          return TRUE;
  1050.       default:
  1051.          return FALSE;
  1052.       }
  1053.    }
  1054.  
  1055.